import express, { type Application, type Response } from "express"
import { fileURLToPath } from "node:url"
import path from "path"
import fs from "fs"
import { isSupportWebp } from "../utils/helper"
import loggerTool from "../utils/logger"
import { createServer as createViteServer, type ViteDevServer } from "vite"
import { createRequire } from "module" // Bring in the ability to create the 'require' method

const require = createRequire(import.meta.url) // construct the require method
const isProd = process.env.NODE_ENV !== "development"
const disablePageCache = process.env.DISABLE_PAGE_CACHE === "true"
const v = process.env.npm_package_version || process.env.version
const logger = loggerTool(import.meta.url)

const __dirname = path.dirname(fileURLToPath(import.meta.url))
const resolve = (p: string) => path.resolve(__dirname, p)

let vite: ViteDevServer

/**
 * @description 将渲染的html模版数据缓存到redis中
 * @param req 请求头
 * @param rep 响应头
 * @param startDate 生成模版的时间戳
 * @param needCache 是否需要缓存到redis中
 * @param needCache 是否需要发送模版
 */
export const renderToRedis = async (
  req: any,
  // req: Request,
  res: Response,
  startDate: number,
  needSend = true
) => {
  const url = req.originalUrl
  const template = isProd
    ? fs.readFileSync(resolve("../public/client/index.html"), "utf-8")
    : await vite.transformIndexHtml(url, fs.readFileSync(path.resolve(__dirname, "../../index.html"), "utf-8"))
  // @ts-ignore
  const { render } = isProd ? await import("../public/server/entry-server.js") : await vite.ssrLoadModule("/src/entry-server")
  // @ts-ignore
  const manifest: Record<string, string[]> = isProd ? require("../public/client/ssr-manifest.json") : {}

  const userInfo = {
    token: req.cookies.token,
    status: req.cookies.loginStatus
  }
  const context = {
    url: req.url,
    ip: req.customersIp!,
    uuid: req.uuid!,
    abTestStr: req.abTestStr!,
    // locales: getLocales(req),
    isSupportWebp: isSupportWebp(req.get("user-agent")),
    userAgent: req.get("user-agent")!,
    fullUrl: req.fullUrl!,
    sourceChannel: req.cookies.g_SOURCE,
    initAppInfo: req.get("pp-app-info"),
    title: "",
    meta: {
      keywords: "",
      description: ""
    },
    renderPreloadLink: ""
  }

  try {
    const [renderedHtml, state, preloadLinks, cssCollect] = await render(url, context )

    const title = context.title
    const meta = generateMetaTag(context.meta)
    const renderPreloadLink = context.renderPreloadLink
    // 5. 注入渲染后的应用程序 HTML 到模板中。
    const html = template
      .replace(`<!--ssr-outlet-->`, renderedHtml)
      .replace(`<!--pinia-state-->`, `<script>window.__INITIAL_STATE__ = ${state}</script>`)
      .replace("<!--title-->", title)
      .replace("<!--meta-->", meta)
      .replace("<!--ssr-style-->", `<style>${cssCollect}</style>`)
      .replace("<!--preload-links-->", preloadLinks)
      .replace("<!--render-preload-links-->", renderPreloadLink)

    // 6. 返回渲染后的 HTML。
    if (needSend) {
      res.send(html)
    }
    logger.verbose(
      `\x1b[43;30mRENDER\x1b[0;32m Vue html from${needSend ? " " : " Re "}renderToString in \x1b[0;33m${
        Date.now() - startDate
      }ms \x1b[32mUrl:\x1b[4m${req.url}\x1b[0m`
    )
  } catch (e) {
    console.log((e as Error).stack)
    if (!isProd) {
      vite.ssrFixStacktrace(e as Error)
    }
    res.status(500).end((e as Error).stack)
  }
}


function generateMetaTag(meta: { keywords: string; description: string }) {
  return Object.keys(meta).reduce((str, prop) => {
    return meta[prop] ? str.concat(`<meta name="${prop}" content="${meta[prop]}" />`) : str
  }, "")
}

export const render = (req: Request, res: Response) => {
  const startDate = Date.now()
  renderToRedis(req, res, startDate)
}

export const createBundleRender = async (app: Application) => {
  if (!isProd) {
    vite = await createViteServer({
      logLevel: "info",
      server: {
        middlewareMode: true,
        watch: {
          // During tests we edit the files too fast and sometimes chokidar
          // misses change events, so enforce polling for consistency
          usePolling: true,
          interval: 100
        }
      },
      appType: "custom"
    })
    // use vite's connect instance as middleware
    app.use(vite.middlewares)
  } else {
    app.use((await import("compression")).default())
    // app.use(
    //   "/assets",
    //   express.static(resolve("../public/client/assets"), {
    //     maxAge: "24h" // 设置缓存时间
    //   })
    // )

    app.use(
      "/",
      express.static(resolve("../public/client"), {
        maxAge: "24h" // 设置缓存时间
      })
    )
  }
}
